package com.nio.c5_网络编程.selector.readServer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author： pang-yun
 * @date： 2021-09-07 15:42
 * 功能目的 ：用于  selector 用于读
 */
/*
* read  异常处理： 需要取消事件  一个是 正常断开时  另一个是 异常断开时
* */



public class SelectorReadServer {
    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);

        // 将sscKey 放入到selector 的集合之中  关注的是accept 关注的是 serverSocketChannel 中发生的accept 事件
        SelectionKey sscKey = ssc.register(selector, SelectionKey.OP_ACCEPT, null);
        ssc.bind(new InetSocketAddress(9999));

        while (true) {
            //运行到这里停止  因为没有事件时  会阻塞   直到有事件进来
            selector.select();
            // 这里会创建一个 发生事件的  集合
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();  // 即用即删  防止下一次出现空指针异常！！！！
                // 接下来开始 区分 处理 其他各种事件
                if (key.isAcceptable()) {  // accept 事件  建立新的连接
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    /*socketChannel  会出现nullPointerException 空指针异常  因为第一次建立连接之后 会处理事件 将accept 删除 但是不会删除事件
                     * 下次仍会读到这个事件  但是没有连接需要处理  会发生空指针异常
                     * */
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ, null);
                } else if (key.isReadable()) {  // read 事件   原来的连接 发来新的数据
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(8);
                    try {
                        int read = socketChannel.read(byteBuffer);
                        // 正常断开 取消事件
                        if (read == -1) {
                            key.cancel();
                        }
                        if (read > 0) {
                            byteBuffer.flip();
                            while (byteBuffer.hasRemaining()) {
                                byte b = byteBuffer.get();
                                System.out.print((char) b);
                            }
                            byteBuffer.clear();
                            System.out.println();
                        }
                        // 异常断开时 取消事件
                    } catch (IOException e) {
                        key.cancel();
                    }

                }


            }
        }
    }
}
